<?php
namespace Modules\Ddtalk\Lib;
use S\Cache;

/**
 * jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下，jsapi_ticket的有效期为7200秒，通过access_token来获取。
 * 由于获取jsapi_ticket的api调用次数非常有限，频繁刷新jsapi_ticket会导致api调用受限，影响自身业务，开发者必须在自己的服务全局缓存jsapi_ticket 。
 * jsapi_ticket 至少保留90Byte空间
 */
class JSAPI {

	const API_PATH_JSAPI         = '/get_jsapi_ticket';
	const JSAPI_TICKET_CACHE_KEY = '__THIS_IS_DDTALK_JS_API_TICKET__';

	/**
	 * @var array(
	 *      token
	 *      expire
	 * )
	 */
	private static $ticket  = array();
	private static $db      = null;
	/**
	 * 失效时间点
	 * @var int
	 */
	private static $expireat = 0;

	/**
	 * 从存储中获取jsapi_ticket
	 */
	public static function get($all=false, $reset=false) {
		if (!self::$ticket || $reset || time() - self::$expireat > 0) {
			$ticket = self::store()->get(self::JSAPI_TICKET_CACHE_KEY);
			if (empty($ticket)) {
				throw new Exception("获取jsapi_ticket异常", 30002);
			}

			self::$ticket = json_decode($ticket, true);
			self::$expireat = time() + 300;
		}

		return $all ? self::$ticket : self::$ticket['ticket'];
	}

	/**
	 * 获取并存储jsapi_ticket
	 * @link http://ddtalk.github.io/dingTalkDoc/?spm=a3140.7785475.0.0.Q5c5r7#js接口api
	 *
	 * @return array {"errcode":0,"errmsg":"ok","ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA","expires_in":7200}
	 */
	public static function fetch() {
		$ticket = '';

		for ($i=0; $i<3; $i++) {
			$ticket = Util::request(self::API_PATH_JSAPI, array(), true, 'get');
			if ($ticket) {
				// 记录下来供本次请求使用
				self::$ticket = array(
					'ticket'    => $ticket['ticket'],
					'expire'    => time() - 15 + $ticket['expires_in']
				);
				break;
			}
		}
		return $ticket;
	}

	/**
	 * 将从微信接口获取到的 jsapi_ticket 写入存储
	 *
	 * @param $ticket
	 *
	 * @return array|bool
	 */
	public static function set(array $ticket) {
		$ticketToStore = array(
			'ticket'     => $ticket['ticket'],
			'expire'    => time() - 15 + $ticket['expires_in']
		);

		$result = self::store()->set(self::JSAPI_TICKET_CACHE_KEY, json_encode($ticketToStore), 7200);

		return $result ? $ticket : $result;
	}

	/**
	 * 获取存储
	 * @return \S\Cache\Abstraction
	 */
	protected static function store() {
		if(!self::$db){
			self::$db = Cache::pool('redis', 'common');
		}
		return self::$db;
	}


	/**
	 * 获取jsapi调用的配置信息,可以直接输出到页面上作为js对象
	 *
	 * @return string
	 * @throws Exception
	 */
	public static function getConfig() {
		$corpid     = \S\Config::confSecurity('ddtalk.corpid');
		$agentid    = \S\Config::confSecurity('ddtalk.agentid');
		$nonce      = \S\Util\Rand::digit(6);
		$timestamp  = time();
		$url        = \S\Request::getCurrentUrl();
		$ticket     = self::get();

		return array(
			'url'       => $url,
			'agentid'   => $agentid,
			'corpid'    => $corpid,
			'nonce'     => $nonce,
			'timestamp' => $timestamp,
			'signature' => self::sign($ticket, $nonce, $timestamp, $url)
		);
	}

	private static function sign($ticket, $nonce, $timestamp, $url) {
		$plain = 'jsapi_ticket=' . $ticket
			. '&noncestr=' . $nonce
			. '&timestamp=' . $timestamp
			. '&url=' . $url;
		return sha1($plain);
	}
}